//
// Created by 黄扬航 on 2023/9/30.
//
#include <ws2tcpip.h>
#include"Server.h"
#include<WS2tcpip.h>
bool Server::ServerInit() {
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        std::cerr << "Failed to initialize winsock" << std::endl;
        return -1;
    }
    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket == INVALID_SOCKET) {
        std::cerr << "Failed to create server socket." << std::endl;
        WSACleanup();
        return -1;
    }
    sockaddr_in serverAddr{};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(8888);
    if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        std::cerr << "Failed to bind server socket." << std::endl;
        closesocket(serverSocket);
        WSACleanup();
        return -1;
    }
    if (listen(serverSocket, MAX_CLIENTS) == SOCKET_ERROR) {
        std::cerr << "Failed to listen on server socket." << std::endl;
        closesocket(serverSocket);
        WSACleanup();
        return -1;
    }
    sockaddr_in local_addr;
    memset(&local_addr, 0, sizeof(local_addr));
    std::cout << "Server started. Waiting for connections..." << std::endl;
    ServerSocket =  serverSocket;
    ServerAddr =  serverAddr;
}

int Server::NotifiyClient(SOCKET Client, int NoticeType,message Message) {
    if(NoticeType == Pull_New_Message)
    {
        bool AckCheck = false;
        char buffer = Pull_New_Message;
        char *Ack;
        do {
            SetTimeOut(Client);
            send(Client, &buffer, sizeof(buffer), 0);
            recv(Client, Ack, 4, 0);
            Ack == "ACK" ? AckCheck=true:AckCheck=false;
        }
        while(AckCheck);
        return CheckSendACK(Client,sizeof(buffer),Notify_ACK,Message);
    }
}

int Server::AcceptClient() {
    while(true)
    {
        SOCKET Client;
        sockaddr_in ClientAddr{};
        int size = sizeof(ClientAddr);
        Client = accept(ServerSocket, (struct sockaddr*)&ClientAddr, &size);
        if (Client == INVALID_SOCKET) {
            closesocket(Client);
        }
        else
        {
            std::cout<<"new client in,clint id :"<<CurrentId<<std::endl;
            std::string temp =std::to_string(CurrentId);
            send(Client,temp.c_str(),sizeof(std::to_string(CurrentId)),0);
            ClientItems.emplace_back(Client,ClientAddr,CurrentId++);
            return Client;
        }
    }
}
void Server::StartAcceptClient()
{
    std::thread AcceptThread(&Server::AcceptClient,this);
    AcceptThread.detach();
}
int Server::AcceptShortClient(SOCKET client) {
    int count = 0;
    while (m_isRunning) {
        std::cout << ++count << std::endl;
        sockaddr_in clientaddr;
        int size = sizeof(clientaddr);
        listen(client, 0);
        SOCKET newclient = accept(client, (struct sockaddr*)&clientaddr, &size);
        if (newclient == SOCKET_ERROR) {
            closesocket(newclient);
            continue;
        }
        char messagetype = 0;
        recv(newclient, &messagetype, sizeof(messagetype), 0);
        message Message = DealNewMessage(client, messagetype);
        NotifiyClient(FindSocketInfo(client)->ClientID, Pull_New_Message, Message);
    }
}
ClientInfo* Server::FindSocketInfo(SOCKET client)
{
    return &(*std::find_if(ClientItems.begin(), ClientItems.end(), [&client](const auto& item){
        return item.ClientSocket == client;
    }));
}
ClientInfo* Server::FindSocketInfo(int clientID)
{
    return &(*std::find_if(ClientItems.begin(), ClientItems.end(), [&clientID](const auto& item){
        return item.ClientID == clientID;
    }));
}
message Server::DealNewMessage(SOCKET client,int messagetype) {
    if(messagetype == 0)  //client push新消息
    {
        char *recvBuffer;
        recv(client,recvBuffer,sizeof(message),0);
        message ReceivedMessage;
        memcpy(&ReceivedMessage, recvBuffer, sizeof(message));
        auto clientinfo = FindSocketInfo(client);
        ReceivedMessage.SquenceId = clientinfo->CurrentMessageID++;
        clientinfo->Message.emplace_back(ReceivedMessage);
        send(client,"success",sizeof("success"),0);
        NotifiyClient(client,Pull_New_Message,ReceivedMessage);
        closesocket(client);
        return ReceivedMessage;
    }
    else if(messagetype == 1)  //client pull新消息
    {
        char MessageSequenceId = 0;
        recv(client,&MessageSequenceId,sizeof(MessageSequenceId),0);
        auto clientinfo = FindSocketInfo(client);

        while(clientinfo->CurrentMessagePtr!=MessageSequenceId)
        {
            char *Check;
            auto Message = (clientinfo->Message)[clientinfo->CurrentMessagePtr].Message;
            send(client,Message.c_str(),sizeof(Message),0);
            recv(client,Check,8,0);
            if(Check == "Failed!") continue;
            clientinfo->CurrentMessagePtr++;
        }
        send(client,"Done",sizeof("Done"),0);
        closesocket(client);
    }

}

int Server::CheckSendACK(SOCKET TempCLient, int message_length,int ACK_Type,message & Message) {
    if(ACK_Type == MSG_ACK)
    {
        int ACK;
        setsockopt(TempCLient,SOL_SOCKET,SO_SNDTIMEO ,(char*)&Recevtimeout,sizeof(Recevtimeout));
        int result = send(TempCLient, (char *)ACK, sizeof(ACK), 0);
        if(result <=0)
            return -1;
        else return 0;
    }
    else if(ACK_Type == Notify_ACK)
    {
        int ACK;
        setsockopt(TempCLient,SOL_SOCKET,SO_RCVTIMEO ,(char*)&Recevtimeout,sizeof(Recevtimeout));
        recv(TempCLient, (char *)ACK, sizeof(ACK), 0);
        if (ACK == message_length + 1)
        {
            Message.IsSafe =true;
            closesocket(TempCLient);
            return 0;
        }
        else
        {
            std::cerr<<"Error Send Message , Please try again"<<std::endl;
            return -1;
        }
    }
}

void Server::AcceptShortClientThread(SOCKET client) {
    std::thread Thread = std::thread(&Server::AcceptShortClient,this,client);
    Thread.detach();
}

int Server::SetTimeOut(SOCKET &socket) {
    fd_set rset;
    FD_ZERO(&rset);
    FD_SET(socket, &rset);
    return select(socket + 1, &rset, nullptr, nullptr, &timeout);
}

void Server::StartAcceptShortClientThread(SOCKET client) {
    m_isRunning = true;
    std::thread acceptThread(&Server::AcceptShortClient, this, client);
    std::cout<<"creat success\n";
    //acceptThread.detach();
    std::cout<<"detach success\n";
}
void Server::StopAcceptShortClientThread() {
    m_isRunning = false;
}
